{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1Pi_B2cvdBiW"
      },
      "source": [
        "##### Copyright 2018 The TF-Agents Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "nQnmcm0oI1Q-"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3NFuTvWVZG_B"
      },
      "source": [
        "# 정책\n",
        "\n",
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td><a target=\"_blank\" href=\"https://www.tensorflow.org/agents/tutorials/3_policies_tutorial\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\">TensorFlow.org에서 보기</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ko/agents/tutorials/3_policies_tutorial.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\">Google Colab에서 실행하기</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ko/agents/tutorials/3_policies_tutorial.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">GitHub에서 소스 보기</a></td>\n",
        "  <td><a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ko/agents/tutorials/3_policies_tutorial.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\">노트북 다운로드하기</a></td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "31uij8nIo5bG"
      },
      "source": [
        "## 소개"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PqFn7q5bs3BF"
      },
      "source": [
        "강화 학습 용어에서 정책은 환경의 관찰 값을 행동 또는 행동에 대한 분포로 매핑합니다. TF-Agents에서 환경의 관찰 값은 명명된 튜플 `TimeStep('step_type', 'discount', 'reward', 'observation')`에 포함되며, 정책은 타임스텝을 행동 또는 행동 분포에 매핑합니다. 대부분의 정책은 `timestep.observation`을 사용하고 일부 정책은 `timestep.step_type`(예: 상태 저장 정책에서 에피소드 시작 시 상태 재설정)을 사용하지만, `timestep.discount` 및 `timestep.reward`는 일반적으로 무시됩니다.\n",
        "\n",
        "정책은 다음과 같은 방식으로 TF-Agents의 다른 구성 요소와 관련됩니다. 대부분의 정책에는 TimeSteps로부터 행동 및/또는 행동에 대한 분포를 계산하는 신경망이 있습니다. 에이전트는 여러 가지 목적으로 하나 이상의 정책을 포함할 수 있습니다(예: 배포를 위해 훈련되는 기본 정책 및 데이터 수집을 위한 노이즈 정책). 정책을 저장/복원할 수 있으며 데이터 수집, 평가 등을 위해 에이전트와 독립적으로 사용할 수 있습니다.\n",
        "\n",
        "일부 정책은 Tensorflow로 작성하기가 더 쉽고(예: 신경망이 있는 정책) 다른 정책은 Python으로 작성하기가 더 쉽습니다(예: 행동의 스크립트 수행). 따라서 TF 에이전트에서는 Python 및 Tensorflow 정책을 모두 허용합니다. 또한, TensorFlow로 작성된 정책은 Python 환경에서 사용해야 하며 그 반대의 경우도 마찬가지입니다. 예를 들어, TensorFlow 정책은 훈련에 사용되지만, 나중에 운영 Python 환경에 배포됩니다. 이를 쉽게 하기 위해 Python과 TensorFlow 정책 간 변환을 위한 래퍼를 제공합니다.\n",
        "\n",
        "또 다른 흥미로운 정책 클래스는 특정 유형의 노이즈를 추가하거나 확률적 정책의 최대(greedy) 또는 엡실론 최대(epsilon-greedy) 버전을 만들고 여러 정책을 무작위로 혼합하는 등 특정 방식으로 주어진 정책을 수정하는 정책 래퍼입니다. "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HdnG_TT_amWH"
      },
      "source": [
        "## 설정"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9Meq2nT_aquh"
      },
      "source": [
        "tf-agents를 아직 설치하지 않은 경우, 다음을 실행합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "xsLTHlVdiZP3"
      },
      "outputs": [],
      "source": [
        "!pip install tf-agents"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "sdvop99JlYSM"
      },
      "outputs": [],
      "source": [
        "from __future__ import absolute_import\n",
        "from __future__ import division\n",
        "from __future__ import print_function\n",
        "\n",
        "import abc\n",
        "import tensorflow as tf\n",
        "import tensorflow_probability as tfp\n",
        "import numpy as np\n",
        "\n",
        "from tf_agents.specs import array_spec\n",
        "from tf_agents.specs import tensor_spec\n",
        "from tf_agents.networks import network\n",
        "\n",
        "from tf_agents.policies import py_policy\n",
        "from tf_agents.policies import random_py_policy\n",
        "from tf_agents.policies import scripted_py_policy\n",
        "\n",
        "from tf_agents.policies import tf_policy\n",
        "from tf_agents.policies import random_tf_policy\n",
        "from tf_agents.policies import actor_policy\n",
        "from tf_agents.policies import q_policy\n",
        "from tf_agents.policies import greedy_policy\n",
        "\n",
        "from tf_agents.trajectories import time_step as ts\n",
        "\n",
        "tf.compat.v1.enable_v2_behavior()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NyXO5-Aalb-6"
      },
      "source": [
        "## Python 정책"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DOtUZ1hs02bu"
      },
      "source": [
        "Python 정책의 인터페이스는 `policies/py_policy.PyPolicy`에 정의되어 있습니다. 주요 메서드는 다음과 같습니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "4PqNEVls1uqc"
      },
      "outputs": [],
      "source": [
        "class Base(object):\n",
        "\n",
        "  @abc.abstractmethod\n",
        "  def __init__(self, time_step_spec, action_spec, policy_state_spec=()):\n",
        "    self._time_step_spec = time_step_spec\n",
        "    self._action_spec = action_spec\n",
        "    self._policy_state_spec = policy_state_spec\n",
        "\n",
        "  @abc.abstractmethod\n",
        "  def reset(self, policy_state=()):\n",
        "    # return initial_policy_state.\n",
        "    pass\n",
        "\n",
        "  @abc.abstractmethod\n",
        "  def action(self, time_step, policy_state=()):\n",
        "    # return a PolicyStep(action, state, info) named tuple.\n",
        "    pass\n",
        "\n",
        "  @abc.abstractmethod\n",
        "  def distribution(self, time_step, policy_state=()):\n",
        "    # Not implemented in python, only for TF policies.\n",
        "    pass\n",
        "\n",
        "  @abc.abstractmethod\n",
        "  def update(self, policy):\n",
        "    # update self to be similar to the input `policy`.\n",
        "    pass\n",
        "\n",
        "  @property\n",
        "  def time_step_spec(self):\n",
        "    return self._time_step_spec\n",
        "\n",
        "  @property\n",
        "  def action_spec(self):\n",
        "    return self._action_spec\n",
        "\n",
        "  @property\n",
        "  def policy_state_spec(self):\n",
        "    return self._policy_state_spec"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "16kyDKk65bka"
      },
      "source": [
        "가장 중요한 메서드는 환경의 관찰 값을 포함하는 `time_step`을 다음 속성이 포함된 PolicyStep 명명된 튜플에 매핑하는 `action(time_step)`입니다.\n",
        "\n",
        "- `action`: 환경에 적용할 행동\n",
        "- `state`: 다음 행동 호출에 제공될 정책의 상태(예: RNN 상태)\n",
        "- `info`: 행동 로그 확률과 같은 선택적 보조 정보\n",
        "\n",
        "`time_step_spec` 및 `action_spec`은 입력 타임스텝 및 출력 행동의 사양입니다. 정책에는 일반적으로 상태 저장 정책에서 상태를 재설정하는 데 사용되는 `reset` 함수가 있습니다. `update(new_policy)` 함수는 `new_policy` 쪽으로 `self`를 업데이트합니다.\n",
        "\n",
        "이제 Python 정책의 몇 가지 예제를 살펴보겠습니다.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YCH1Hs_WlmDT"
      },
      "source": [
        "### 예제 1: 임의 Python 정책"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lbnQ0BQ3_0N2"
      },
      "source": [
        "`PyPolicy`의 간단한 예제는 주어진 불연속/연속 action_spec에 대한 무작위 행동을 생성하는 `RandomPyPolicy`입니다. 입력 `time_step`은 무시됩니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "QX8M4Nl-_0uu"
      },
      "outputs": [],
      "source": [
        "action_spec = array_spec.BoundedArraySpec((2,), np.int32, -10, 10)\n",
        "my_random_py_policy = random_py_policy.RandomPyPolicy(time_step_spec=None,\n",
        "    action_spec=action_spec)\n",
        "time_step = None\n",
        "action_step = my_random_py_policy.action(time_step)\n",
        "print(action_step)\n",
        "action_step = my_random_py_policy.action(time_step)\n",
        "print(action_step)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "B8WrFOR1lz31"
      },
      "source": [
        "### 예제 2: 스크립팅된 Python 정책"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "AJ0Br1lGBnTT"
      },
      "source": [
        "스크립팅된 정책은 `(num_repeats, action)` 튜플의 목록으로 표시되는 행동의 스크립트를 재생합니다. `action` 함수가 호출될 때마다 지정된 반복 횟수가 완료될 때까지 목록에서 다음 행동을 반환한 후 목록의 다음 행동으로 이동합니다. `reset` 메서드를 호출하여 목록의 처음부터 실행을 시작할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "_mZ244m4BUYv"
      },
      "outputs": [],
      "source": [
        "action_spec = array_spec.BoundedArraySpec((2,), np.int32, -10, 10)\n",
        "action_script = [(1, np.array([5, 2], dtype=np.int32)), \n",
        "                 (0, np.array([0, 0], dtype=np.int32)), # Setting `num_repeats` to 0 will skip this action.\n",
        "                 (2, np.array([1, 2], dtype=np.int32)), \n",
        "                 (1, np.array([3, 4], dtype=np.int32))]\n",
        "\n",
        "my_scripted_py_policy = scripted_py_policy.ScriptedPyPolicy(\n",
        "    time_step_spec=None, action_spec=action_spec, action_script=action_script)\n",
        "\n",
        "policy_state = my_scripted_py_policy.get_initial_state()\n",
        "time_step = None\n",
        "print('Executing scripted policy...')\n",
        "action_step = my_scripted_py_policy.action(time_step, policy_state)\n",
        "print(action_step)\n",
        "action_step= my_scripted_py_policy.action(time_step, action_step.state)\n",
        "print(action_step)\n",
        "action_step = my_scripted_py_policy.action(time_step, action_step.state)\n",
        "print(action_step)\n",
        "\n",
        "print('Resetting my_scripted_py_policy...')\n",
        "policy_state = my_scripted_py_policy.get_initial_state()\n",
        "action_step = my_scripted_py_policy.action(time_step, policy_state)\n",
        "print(action_step)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3Dz7HSTZl6aU"
      },
      "source": [
        "## TensorFlow 정책"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LwcoBXqKl8Yb"
      },
      "source": [
        "TensorFlow 정책은 Python 정책과 같은 인터페이스를 따릅니다. 몇 가지 예제를 살펴보겠습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3x8pDWEFrQ5C"
      },
      "source": [
        "### 예제 1: 임의 TF 정책\n",
        "\n",
        "RandomTFPolicy는 주어진 불연속/연속 `action_spec`에 따라 무작위 행동을 생성하는 데 사용될 수 있습니다. 입력`time_step`은 무시됩니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "nZ3pe5G4rjrW"
      },
      "outputs": [],
      "source": [
        "action_spec = tensor_spec.BoundedTensorSpec(\n",
        "    (2,), tf.float32, minimum=-1, maximum=3)\n",
        "input_tensor_spec = tensor_spec.TensorSpec((2,), tf.float32)\n",
        "time_step_spec = ts.time_step_spec(input_tensor_spec)\n",
        "\n",
        "my_random_tf_policy = random_tf_policy.RandomTFPolicy(\n",
        "    action_spec=action_spec, time_step_spec=time_step_spec)\n",
        "observation = tf.ones(time_step_spec.observation.shape)\n",
        "time_step = ts.restart(observation)\n",
        "action_step = my_random_tf_policy.action(time_step)\n",
        "\n",
        "print('Action:')\n",
        "print(action_step.action)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GOBoWETprWCB"
      },
      "source": [
        "### 예제 2: Actor 정책\n",
        "\n",
        "Actor 정책은 `time_steps`를 행동에 매핑하는 네트워크 또는 `time_steps`를 행동에 대한 분포에 매핑하는 네트워크를 사용하여 생성됩니다.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2S94E5zQgge_"
      },
      "source": [
        "#### 행동 네트워크 사용하기"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "X2LM5STNgv1u"
      },
      "source": [
        "다음과 같이 네트워크를 정의합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "S2wFgzJFteQX"
      },
      "outputs": [],
      "source": [
        "class ActionNet(network.Network):\n",
        "\n",
        "  def __init__(self, input_tensor_spec, output_tensor_spec):\n",
        "    super(ActionNet, self).__init__(\n",
        "        input_tensor_spec=input_tensor_spec,\n",
        "        state_spec=(),\n",
        "        name='ActionNet')\n",
        "    self._output_tensor_spec = output_tensor_spec\n",
        "    self._sub_layers = [\n",
        "        tf.keras.layers.Dense(\n",
        "            action_spec.shape.num_elements(), activation=tf.nn.tanh),\n",
        "    ]\n",
        "\n",
        "  def call(self, observations, step_type, network_state):\n",
        "    del step_type\n",
        "\n",
        "    output = tf.cast(observations, dtype=tf.float32)\n",
        "    for layer in self._sub_layers:\n",
        "      output = layer(output)\n",
        "    actions = tf.reshape(output, [-1] + self._output_tensor_spec.shape.as_list())\n",
        "\n",
        "    # Scale and shift actions to the correct range if necessary.\n",
        "    return actions, network_state"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "k7fIn-ybVdC6"
      },
      "source": [
        "TensorFlow에서 대부분의 네트워크 레이어는 배치 연산을 위해 설계되었으므로 입력 time_steps가 배치 처리되고 네트워크의 출력도 배치 처리됩니다. 또한, 네트워크는 주어진 action_spec의 올바른 범위에서 행동을 생성할 책임이 있습니다. 일반적으로, 예를 들어 최종 레이어에 대한 tanh 활성화를 사용하여 [-1, 1]에서의 행동을 생성한 다음 이를 입력 action_spec과 같은 올바른 범위로 조정하고 이동하면 됩니다(예: `tf_agents/agents/ddpg/networks.actor_network()`).\n",
        "\n",
        "이제 위의 네트워크를 사용하여 actor 정책을 만들 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "0UGmFTe7a5VQ"
      },
      "outputs": [],
      "source": [
        "input_tensor_spec = tensor_spec.TensorSpec((4,), tf.float32)\n",
        "time_step_spec = ts.time_step_spec(input_tensor_spec)\n",
        "action_spec = tensor_spec.BoundedTensorSpec((3,),\n",
        "                                            tf.float32,\n",
        "                                            minimum=-1,\n",
        "                                            maximum=1)\n",
        "\n",
        "action_net = ActionNet(input_tensor_spec, action_spec)\n",
        "\n",
        "my_actor_policy = actor_policy.ActorPolicy(\n",
        "    time_step_spec=time_step_spec,\n",
        "    action_spec=action_spec,\n",
        "    actor_network=action_net)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xlmGPTAmfPK3"
      },
      "source": [
        "time_step_spec 다음에 오는 모든 time_steps 배치에 적용할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "fvsIsR0VfOA4"
      },
      "outputs": [],
      "source": [
        "batch_size = 2\n",
        "observations = tf.ones([2] + time_step_spec.observation.shape.as_list())\n",
        "\n",
        "time_step = ts.restart(observations, batch_size)\n",
        "\n",
        "action_step = my_actor_policy.action(time_step)\n",
        "print('Action:')\n",
        "print(action_step.action)\n",
        "\n",
        "distribution_step = my_actor_policy.distribution(time_step)\n",
        "print('Action distribution:')\n",
        "print(distribution_step.action)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lumtyhejZOXR"
      },
      "source": [
        "위의 예제에서는 행동 텐서를 생성하는 행동 네트워크를 사용하여 정책을 만들었습니다. 이 경우, `policy.distribution(time_step)`은 `policy.action(time_step)`의 출력 주위에서의 결정적(델타) 분포입니다. 확률적 정책을 생성하는 한 가지 방법은 행동에 노이즈를 추가하는 정책 래퍼로 actor 정책을 래핑하는 것입니다. 또 다른 방법은 아래와 같이 행동 네트워크 대신 행동 분포 네트워크를 사용하여 actor 정책을 만드는 것입니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_eNrJ5gKgl3W"
      },
      "source": [
        "#### 행동 분포 네트워크 사용하기"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "sSYzC9LobVsK"
      },
      "outputs": [],
      "source": [
        "class ActionDistributionNet(ActionNet):\n",
        "\n",
        "  def call(self, observations, step_type, network_state):\n",
        "    action_means, network_state = super(ActionDistributionNet, self).call(\n",
        "        observations, step_type, network_state)\n",
        "\n",
        "    action_std = tf.ones_like(action_means)\n",
        "    return tfp.distributions.Normal(action_means, action_std), network_state\n",
        "\n",
        "\n",
        "action_distribution_net = ActionDistributionNet(input_tensor_spec, action_spec)\n",
        "\n",
        "my_actor_policy = actor_policy.ActorPolicy(\n",
        "    time_step_spec=time_step_spec,\n",
        "    action_spec=action_spec,\n",
        "    actor_network=action_distribution_net)\n",
        "\n",
        "action_step = my_actor_policy.action(time_step)\n",
        "print('Action:')\n",
        "print(action_step.action)\n",
        "distribution_step = my_actor_policy.distribution(time_step)\n",
        "print('Action distribution:')\n",
        "print(distribution_step.action)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "BzoNGJnlibtz"
      },
      "source": [
        "위의 예제에서 행동은 주어진 행동 사양 [-1, 1]의 범위로 잘립니다. ActorPolicy의 생성자 인수는 기본적으로 clip = True이기 때문입니다. 이 값을 false로 설정하면 네트워크에서 생성된 잘리지 않은 행동이 반환됩니다. "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PLj6A-5domNG"
      },
      "source": [
        "예를 들어, `stochastic_policy.distribution().mode()`를 행동으로 선택하는, 그리고 이 최대 행동 주변의 결정론적/델타 분포를 `distribution()`으로 선택하는 GreedyPolicy 래퍼를 사용하여 확률적 정책을 결정론적 정책으로 변환할 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4Xxzo2a7rZ7v"
      },
      "source": [
        "### 예제 3: Q 정책"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "79eGLqpOhQVp"
      },
      "source": [
        "Q 정책은 DQN과 같은 에이전트에서 사용되며 각 불연속 행동에 대한 Q 값을 예측하는 Q 네트워크를 기반으로 합니다. 주어진 타임스텝에서 Q 정책의 행동 분포는 q 값을 로짓으로 사용하여 작성된 범주형 분포입니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Haakr2VvjqKC"
      },
      "outputs": [],
      "source": [
        "input_tensor_spec = tensor_spec.TensorSpec((4,), tf.float32)\n",
        "time_step_spec = ts.time_step_spec(input_tensor_spec)\n",
        "action_spec = tensor_spec.BoundedTensorSpec((),\n",
        "                                            tf.int32,\n",
        "                                            minimum=0,\n",
        "                                            maximum=2)\n",
        "num_actions = action_spec.maximum - action_spec.minimum + 1\n",
        "\n",
        "\n",
        "class QNetwork(network.Network):\n",
        "\n",
        "  def __init__(self, input_tensor_spec, action_spec, num_actions=num_actions, name=None):\n",
        "    super(QNetwork, self).__init__(\n",
        "        input_tensor_spec=input_tensor_spec,\n",
        "        state_spec=(),\n",
        "        name=name)\n",
        "    self._sub_layers = [\n",
        "        tf.keras.layers.Dense(num_actions),\n",
        "    ]\n",
        "\n",
        "  def call(self, inputs, step_type=None, network_state=()):\n",
        "    del step_type\n",
        "    inputs = tf.cast(inputs, tf.float32)\n",
        "    for layer in self._sub_layers:\n",
        "      inputs = layer(inputs)\n",
        "    return inputs, network_state\n",
        "\n",
        "\n",
        "batch_size = 2\n",
        "observation = tf.ones([batch_size] + time_step_spec.observation.shape.as_list())\n",
        "time_steps = ts.restart(observation, batch_size=batch_size)\n",
        "\n",
        "my_q_network = QNetwork(\n",
        "    input_tensor_spec=input_tensor_spec,\n",
        "    action_spec=action_spec)\n",
        "my_q_policy = q_policy.QPolicy(\n",
        "    time_step_spec, action_spec, q_network=my_q_network)\n",
        "action_step = my_q_policy.action(time_steps)\n",
        "distribution_step = my_q_policy.distribution(time_steps)\n",
        "\n",
        "print('Action:')\n",
        "print(action_step.action)\n",
        "\n",
        "print('Action distribution:')\n",
        "print(distribution_step.action)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Xpu9m6mvqJY-"
      },
      "source": [
        "## 정책 래퍼"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "OfaUrqRAoigk"
      },
      "source": [
        "정책 래퍼를 사용하여 주어진 정책을 래핑하고 수정할 수 있습니다(예: 노이즈 추가). 정책 래퍼는 정책 (Python/TensorFlow)의 서브 클래스이므로 다른 정책과 마찬가지로 사용할 수 있습니다. "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-JJVVAALqVNQ"
      },
      "source": [
        "### 예제: 최대 정책(Greedy Policy)\n",
        "\n",
        "최대 래퍼(greedy wrapper)를 사용하여 `distribution()`을 구현하는 모든 TensorFlow 정책을 래핑할 수 있습니다. `GreedyPolicy.action()`은 `wrapped_policy.distribution().mode()`를 반환하고, `GreedyPolicy.distribution()`은 `GreedyPolicy.action()` 주위의 결정적/델타 분포입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "xsRPBeLZtXvu"
      },
      "outputs": [],
      "source": [
        "my_greedy_policy = greedy_policy.GreedyPolicy(my_q_policy)\n",
        "\n",
        "action_step = my_greedy_policy.action(time_steps)\n",
        "print('Action:')\n",
        "print(action_step.action)\n",
        "\n",
        "distribution_step = my_greedy_policy.distribution(time_steps)\n",
        "print('Action distribution:')\n",
        "print(distribution_step.action)"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "3_policies_tutorial.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
